home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-09-11 | 29.0 KB | 1,134 lines |
-
-
- c
- c MODEM7-type program to send and
- c receive files with checksums or CRC and automatic
- c re-transmission of bad blocks.
- c translated to VAX Fortran V3.0 from TMODEM.C by
- c and enhanced according to time-outs and CRC
- C in XMODEM50.ASM
- c J.James Belonis II
- c Physics Hall FM-15
- c University of Washington
- c Seattle, WA 98195
- c
- c TMODEM.C written by Richard Conn, Eliot Moss, and Lauren
- c Weinstein
- c
- c 6/30/83 Modified, restructured, and VAX/VMS text file
- c conversion added by Richard Conn
- c 1/17/83 touched up filename display and comments.
- c 1/14/83 including timeouts and CTRL-X cancellation
- c and CRC capability
- c
- c keeps a log file of error messages ( deletes it if no errors )
- c sets terminal driver to eightbit, passall
- c may need altypeahd if faster than 1200 baud works to 9600 baud at least.
- c needs PHY_IO privilege for passall ? apparently not on UWPhys VAX
- c nor on ACC VAX
- c many debugging statements left in as comments
-
- c declare variables
- include 'QIO.DCK'
- character*80 line, file, workf
- integer sloc, worklen
-
- logical filedel
- common /filest/filedel
-
- integer errorcount
- common /err/errorcount
-
- integer high,low
- common /crcval/high,low
-
- logical crc
- integer checksum
- common /checks/checksum,crc
-
- equivalence (checksum,checksumbyte)
- equivalence (ic,c)
-
- c define ascii characters
- parameter NUL=0 !ignore at SOH time
- parameter SOH=1 !start of header for sector
- parameter EOT=4 !end of transfer
- parameter ACK=6 !acknowlege sector
- parameter NAK=21 !not acknowlege sector
- parameter CAN=24 !cancel transfer
- parameter CRCCHAR='C' !CRC indicating character
-
- c timeouts
- parameter respnaklim=10 !seconds to allow for response to NAK
- parameter naklim=10 !seconds to allow to receive first NAK
- parameter eotlim=10 !seconds to wait for EOT acknowlege
-
- parameter errlim=10 !max errors on a sector
-
- c define an exit routine to get control on all exits to turn off
- c passall and for debug cleanup
- external giveup
- call userex( giveup )
-
- print *,' XMODEM Version 5.1 on VAX VMS'
- c log file for debugging
- open(8,file='XMODEM.LOG',carriagecontrol='LIST',status='NEW')
- c assign terminal channel for QIO calls to send raw bytes.
- call sys$assign('TT',chan,,)
-
- c name work file
- workf='XMODEM.WRK '
- worklen=10 ! number of chars in file name
- c get command line
- call lib$get_foreign(line,'$_XMODEM Command: ',)
- c trim blanks
- do i=80,1,-1
- if(line(i:i).NE.' ') goto 25
- len=i
- enddo
- 25 continue
-
- c set to NOT delete working file
- filedel=.false.
-
- c send
- sloc=index(line,'S ')
- if(sloc.NE.0) then
- file=line(sloc+2:)
- len=len-2
- crc=.false.
- print *,' Sending File: ',file(1:len)
- call sendfile(file,len)
- call exit
- endif
- c send text
- sloc=index(line,'ST ')
- if(sloc.NE.0) then
- file=line(sloc+3:)
- len=len-3
- crc=.false.
- print *,' Sending Text File: ',file(1:len)
- call vtoc(file,workf)
- filedel=.true. !delete working file when done
- call sendfile(workf,worklen)
- call exit
- endif
- c send with CRC
- sloc=index(line,'SC ')
- if (sloc.NE.0) then
- file=line(sloc+3:)
- len=len-3
- crc=.true.
- print *,' Sending File: ',file(1:len),' using CRCs'
- call sendfile(file,len)
- call exit
- endif
- c receive with checksum
- sloc=index(line,'R ')
- if(sloc.NE.0) then
- file=line(sloc+2:)
- len=len-2
- crc=.false.
- print *,' Receiving File: ',file(1:len)
- call recvfile(file,len)
- call exit
- endif
- c receive text with checksum
- sloc=index(line,'RT ')
- if(sloc.NE.0) then
- file=line(sloc+3:)
- len=len-3
- crc=.false.
- print *,' Receiving Text File: ',file(1:len)
- call recvfile(workf,worklen)
- filedel=.true. !delete working file when done
- call ctov(workf,file)
- call exit
- endif
- c receive with CRC
- sloc=index(line,'RC ')
- if(sloc.NE.0) then
- file=line(sloc+3:)
- len=len-3
- crc=.true.
- print *,' Receiving File: ',file(1:len),' using CRCs'
- call recvfile(file,len)
- call exit
- endif
-
- c else bad command
- print *,' Invalid XMODEM Command --'
- print *,' Usage: XMODEM <S, ST, SC, R, RT, or RC> <file> '
- print *,' S = Send, R = Receive, C = Use CRCs'
- print *,' T = Convert CP/M to VAX/VMS and VAX/VMS to CP/M Text Files'
- call exit
- end
-
- c----------------------------------------------------------------
- c send file
- subroutine sendfile(file,len)
-
- c declare variables
- include 'QIO.DCK'
- character*80 file
- byte sector(130), c
- integer blocknumber, nakwait, stat, ic
- logical ttyinlim
- logical charintime, acked
-
- logical filedel
- common /filest/filedel
-
- integer errorcount
- common /err/errorcount
-
- integer high,low
- common /crcval/high,low
-
- logical crc
- integer checksum
- common /checks/checksum,crc
-
- equivalence (checksum,checksumbyte)
- equivalence (ic,c)
-
- c define ASCII characters
- parameter NUL=0
- parameter SOH=1
- parameter EOT=4
- parameter ACK=6
- parameter NAK=21
- parameter CAN=24
- parameter CRCCHAR='C'
- c timeouts
- parameter respnaklim=10
- parameter naklim=10
- parameter eotlim=10
- parameter errlim=10
-
- open(6,name=file(1:len),iostat=stat,status='OLD')
- c 1 carriagecontrol='NONE',recordtype='FIXED',recl=128)
-
- if(stat) then
- print *,'Can''t open',file(1:len),' for send.'
- call exit
- endif
- if(crc) then
- print *,' CRC Transfer Mode'
- else
- print *,' Checksum Transfer Mode'
- endif
- print *,file(1:len),' Open -- Please Run Your Receiver --'
- print *
- errorcount=0
- blocknumber=1
- nakwait=0
-
- c await first NAK (or 'C') indicating receiver is ready
- 200 charintime=ttyinlim(c,1,naklim) ! return NUL if timeout
- c print *,' character=',c
- if( .NOT.charintime ) then
- nakwait=nakwait+1
- c give the turkey 80 seconds to figure out how to receive a file
- if(nakwait.EQ.80) call cancel
- goto 200
- elseif(c.EQ.NAK) then
- crc=.false.
- elseif(c.EQ.CRCCHAR) then
- crc=.true.
- elseif(c.EQ.CAN) then
- call cancel
- else
- c unrecognized character
- nakwait=nakwait+1
- if(nakwait.eq.80) call cancel
- goto 200
- endif
-
- 300 continue
- c send new sector
- read(6,1000,end=500) (sector(i),i=1,128)
- 1000 format(128a)
- errorcount=0
- c print *,' sector as read',sector
- 400 continue
- c send sector
- c print *,' SOH '
- call ttyout(SOH,1)
- call ttyout(blocknumber,1)
- call ttyout( not(blocknumber),1 )
- c print *,' blocknumber=',blocknumber
-
- checksum=0
- call clrcrc
- c separate calls to slow down in case other end slow (can even introduce
- c delay between characters).
- c do i=1,128
- c call ttyout(sector(i),1)
- c enddo
- call ttyout(sector,128)
-
- c calc checksum or crc
- if(crc) then
- c put all bytes + two finishing zero bytes through updcrc
- sector(129)=0
- sector(130)=0
- call updcrc( sector,130 )
- call ttyout(high,1)
- call ttyout(low,1)
- else
- do i=1,128
- checksum=checksum+sector(i)
- enddo
- c this sends low order byte of checksum
- call ttyout(checksum,1)
- c print *,' checksum',checksum
- endif
-
- c sector sent, see if receiver acknowleges
- c getack attempts to get ACK
- c if not, repeat sector
- c print*, ' should wait for ACK 10 seconds'
- call getack(acked)
- c print*, ' getack returned=',acked
- if(.NOT.acked) goto 400
-
- c ACK received, send next sector
- blocknumber=blocknumber+1
- goto 300
-
- c end of file during read. finish up sending.
- 500 continue
- call ttyout(EOT,1)
- c getack attempts to get ACK up to errlim times
- call getack(acked)
- if( .NOT.acked ) goto 500
-
- c print *,' Sending complete.'
- if (filedel) then
- close(6,dispose='DELETE')
- else
- close(6)
- endif
- close(8,dispose='DELETE')
- return
- end
-
- c----------------------------------------------------------------
- c receive file
- subroutine recvfile(file,len)
-
- c declare variables
- include 'QIO.DCK'
- character*80 file
- byte sector(130), c, notc, checksumbyte, ck
- integer blocknumber, inotc, notnotc, secbytes, stat
- integer testblock, testprev, ic
- logical ttyinlim
- logical charintime, firstsoh
-
- integer errorcount
- common /err/errorcount
-
- integer high,low
- common /crcval/high,low
-
- logical crc
- integer checksum
- common /checks/checksum,crc
-
- equivalence (checksum,checksumbyte)
- equivalence (ic,c)
-
- c define ASCII characters
- parameter NUL=0
- parameter SOH=1
- parameter EOT=4
- parameter ACK=6
- parameter NAK=21
- parameter CAN=24
- parameter CRCCHAR='C'
- c timeouts
- parameter respnaklim=10
- parameter naklim=10
- parameter eotlim=10
- parameter errlim=10
-
- open(7,name=file(1:len),recl=128,status='NEW',iostat=stat,
- 1 carriagecontrol='NONE',recordtype='FIXED')
- if(stat) then
- print *,' Can''t open ',file(1:len),' for recieve.'
- call exit
- endif
-
- print *,' Please Send Your File --'
- print *
- call passall(CHAN,.TRUE.)
-
- secbytes=129
- if(crc) then
- secbytes=130
- endif
-
- firstsoh=.false.
- errorcount=0
- blocknumber=1
-
- c start the sender by letting ttyinlim time-out in getack routine
- c so it sends a NAK or C
- goto 999
-
- 800 continue
- c write(8,*) ' ready for SOH'
- c must allow enough time for other's disk read (xmodem50.asm allows 10 sec)
- charintime=ttyinlim(c,1,respnaklim)
- c if no char for a while, try NAK or C again
- if( .NOT.charintime ) then
- c print*,' no response to NAK or C, trying again'
- write(8,*) ' no response to NAK or C, trying again'
- goto 999
- endif
- c else received a char so see what it is
- if(c.eq.NUL) goto 800 ! ignore nulls here for compatablity with old
- ! versions of modem7
- if(c.EQ.CAN) then
- print *,' Canceled. Aborting.'
- write(8,*) ' Canceled. Aborting.'
- call exit
- endif
- c write(8,*) ' EOT or SOH character=',c
- if(c.NE.EOT) then
- IF(c.NE.SOH) then
- write(8,*) ' Not SOH, was decimal ',c
- goto 999
- endif
- firstsoh=.true.
-
- c character was SOH to indicate start of header
- c get block number and complement
- call ttyin(c,1)
- c write(8,*) ' block=',c
-
- call ttyin(notc,1)
- c write(8,*) ' block complement=',notc
- inotc=notc ! make integer for "not" function
- notnotc=iand( not(inotc),255 ) ! mask back to byte
-
- c c is low order byte of ic via equivalence statement
- if(ic.NE.notnotc) then
- write(8,*) ' block check bad.'
- goto 999
- endif
- c block number valid but not yet checked against expected
-
- c clear checksum and CRC
- checksum=0
- call clrcrc
-
- c receive the sector and checksum bytes in one call (for speed).
- c secbytes is 129 for checksum, 130 for CRC
- call ttyin(sector,secbytes)
-
- if(crc) then
- c put data AND CRC bytes through updcrc
- call updcrc(sector,secbytes)
- c if result non-zero, BAD.
- if(iand(high,255).NE.0
- 1 .OR.iand(low,255).NE.0) then
- c write(8,*) ' CRC, high,low='
- c write(8,3000) high,low
- c 3000 format(2z10)
- goto 999
- endif
- else
- c don't add received checksum byte to checksum
- do i=1,secbytes-1
- checksum=checksum+sector(i)
- enddo
- ck=sector(129)
- c write(8,2100) ck
-
- c write(8,2100) checksum
- c write(8,2100) checksumbyte
- c 2100 format(' checksum=',z10)
- if( checksumbyte.NE.ck ) then
- write(8,*) ' bad checksum'
- goto 999
- endif
- endif
-
- c received OK so we can believe the block number, see which block it was
- c mask it to be one byte
- testblock=iand(blocknumber,255)
- testprev=iand( blocknumber-1 ,255)
- if( ic.EQ.testprev) then
- write(8,*) ' prev. block again, out of synch'
- c already have this block so don't write it, but ACK anyway to resynchronize
- goto 985
- elseif( ic.NE.testblock ) then
- write(8,*) ' block number bad.'
- goto 999
- endif
- c else was expected block
-
- c write before acknowlege so not have to listen while write.
- write(7,2000,err=900) (sector(i),i=1,128)
- 2000 format(128a)
- goto 975
- 900 write(8,*) ' Can''t write sector. Aborting.'
- print*, ' Can''t write sector. Aborting.'
- call exit
-
- 975 continue
- c recieved sector ok, wrote it ok, so acknowlege it to request next.
- blocknumber=blocknumber+1
- c comes here if re-received the previous sector
- 985 continue
- errorcount=0
- c write(8,*) ' ACKing, sector was ok.'
- call ttyout(ACK,1)
- goto 800
-
- c else error so eat garbage in case out of synch and try again
- 999 continue
- call eat
- write(8,*) ' receive error NAK, block=',blocknumber
- if(crc.AND..NOT.firstsoh) then
- c keep sending 'C' 'til receive first SOH
- call ttyout(CRCCHAR,1)
- else
- call ttyout(NAK,1)
- endif
- errorcount=errorcount+1
- 998 if(errorcount.GE.errlim) then
- print*,' Unable to receive block. Aborting.'
- write(8,*) ' Not receive block. Aborting.'
- c delete incompletely received file
- close(7,dispose='DELETE')
- call exit
- endif
- c retry
- goto 800
- endif
-
- c EOT received instead of SOH so file done.
- c should keep sending ACK 'til no more EOT's ?
- close(6)
- close(7)
- call ttyout(ACK,1)
- call ttyout(ACK,1)
- call ttyout(ACK,1)
-
- c write(8,*) ' Completed.'
- c print *, ' Completed.'
- c transfer ok, so delete the error log file.
- c close(8,status='DELETE')
- close(8,dispose='DELETE')
- return
- end
-
- c-------------------------------------------------------------
- subroutine ctov(input,output)
- c convert file of XMODEM 128 byte records with embedded <CR><LF>
- c marking end-of-line and CTRL-Z marking end-of-file
- c to carriage-control=LIST (normal VAX editable file)
-
- character*80 input,output
- character*300 line
- character*1 CR,LF,recchar
- integer blank
- logical eof, eol
-
- logical filedel
- common /filest/filedel
-
- data eof,eol/.false.,.false./
-
- CR=char(13)
- LF=char(10)
-
- open(6,file=input,status='OLD')
- c set maximum output record length to 300 (fortran default is 133)
- open(7,file=output,status='NEW',carriagecontrol='LIST',recl=300)
-
- c getchar (read new record if no input characters left)
- c if EOF on input, write line and exit
- c if CR then
- c if getchar LF then write line
- c else put back char and putchar CR into line (error if too long)
- c endif
- c else putchar (write error message if line too long)
- c endif
- c loop
-
- 100 call getc(recchar,eof,eol)
- if(eof) goto 200
- if(recchar.eq.CR) then
- c PRINT *,' CR'
- call getc(recchar,eof)
- if(eof.or.recchar.ne.LF) then
- call putback
-
- len=len+1
- if(len.ge.301) print *,' Out line too long.'
- c print*,' too long line=',line
- line(len:len)=recchar
- else
- c was LF
- c PRINT *,' LEN=',LEN
- c print*,' after LF, line=',line(1:len)
- write(7,2000) line(1:len)
- len=0
- endif
- else
- c not CR, was "ordinary" character
- len=len+1
- if(len.ge.301) then
- print *,' Out line too long.'
- c PRINT *,' LINE=',LINE(1:len)
- endif
- line(len:len)=recchar
- endif
-
- go to 100
-
- c flush last line and exit
- 200 continue
- if(len.ne.0) then
- write(7,2000) line(1:len)
- 2000 format(a)
- endif
- if (filedel) then
- close(6,dispose='DELETE')
- else
- close(6)
- endif
- close(7)
- return
- end
- c-------------------------------------------------------------
- subroutine vtoc(input,output)
- c convert VAX text file to
- c file of XMODEM 128 byte records with embedded <CR><LF>
-
- character*80 input,output
- character*1 CR,LF,c
- integer blank
- logical eof,eol
- data eof,eol/.false.,.false./
-
- CR=char(13)
- LF=char(10)
-
- open(6,file=input,status='OLD')
- open(7,file=output,status='NEW',carriagecontrol='LIST',
- 1 recl=128,recordtype='FIXED')
-
- c getchar (read new line if no input characters left)
- c putchar ( output record if full, close if EOF )
- c if EOL on input, putchar CR putchar LF (output record if full)
- c loop
-
- 100 call getv(c,eof,eol)
- if(.not.eol) then
- call putchar(c,eof)
- if(eof) then
- return
- endif
- else
- c end of line
- call putchar(CR,eof)
- call putchar(LF,eof)
- eol=.false.
- if(eof) then
- return
- endif
- endif
- go to 100
-
- end
- c------------------------------------------
- subroutine putchar(c,eof)
- character*1 c
- logical eof
- c put character into record (write record if necessary)
- c if eof, fills out rest of record with CTRL-Z's and exits
- character*1 CTRLZ
- character*128 record
- integer point
- common /reccom/point,record
- data point/0/
-
- if(eof) goto 200
- point=point+1
- c strip parity in case VAX file had it
- record(point:point)=char(iand(ichar(c),127))
- c print*,' record(point:point)=',record(point:point)
- c print*,' point=',point
- 50 if(point.ge.128) then
- c print*,' record=',record
- 100 write(7,1000) record
- 1000 format(a)
- point=0
- endif
- return
-
- c EOF fill record with 26's (CTRL-Z, CP/M end of file mark for ASCII)
- c output last record and exit
- 200 continue
- c print*,' in putchar EOF section'
- CTRLZ=char(26)
- do i=point+1,128
- record(i:i)=CTRLZ
- enddo
- c print*,' record=',record
- write(7,1000) record
- close(6)
- close(7)
- return
- end
- c------------------------------------------
- subroutine getc(c,eof)
- c get character from a CP/M text file
- character*1 c
- logical eof
- c point to next character in record (read record if necessary)
- character*128 record
- character*1 CTRLZ
- integer point
- logical firsttime
- common /reccom/point,record,firsttime
- data point/0/
- data firsttime/.true./
-
- CTRLZ=char(26)
- point=point+1
- if(point.gt.128.or.firsttime) then
- firsttime=.false.
- 100 read(6,1000,end=200) record
- 1000 format(a)
- c PRINT *,RECORD
- point=1
- endif
- c strip parity in case CP/M file had it
- c=char(iand(ichar(record(point:point)),127))
- if(c.eq.CTRLZ) eof=.true.
- return
-
- 200 eof=.true.
- return
- end
- c-------------------------------------------
- subroutine getv(inchar,eof,eol)
- character*1 inchar
- logical eof,eol
- c get character from input line (read line if necessary)
- c returns character and eol=.true. if no more char on line
- c returns eof if end of file (no character)
- character*255 line
- integer len, pos
- logical firsttime
- common/lincom/pos,len,line
- data pos/0/
-
- if(pos.eq.0) then
- read(6,1000,end=100)len,line(1:len)
- 1000 format(q,a)
- c print*,' line=',line
- endif
- pos=pos+1
- if(pos.gt.len) then
- eol=.true.
- pos=0
- return
- endif
- c print*,' pos=',pos,' line(1:pos)=',line(1:pos)
- c print*,' line(pos:pos)=',line(pos:pos)
- inchar=line(pos:pos)
- c print*,' pos,char',pos,inchar
- return
-
- c EOF
- 100 continue
- eof=.true.
- return
- end
- c----------------------------------------------
- subroutine putback
- c point to previous input character so this character will be getchar result
- c even works if 1st char of record
- integer point
- logical eof
- common /reccom/point
-
- point=point-1
- return
- end
-
- c-----------------------------------------------------------
- subroutine clrcrc
- c clears CRC
- integer high,low
- common /crcval/high,low
-
- high=0
- low=0
- return
- end
- c-----------------------------------------------------------
- subroutine updcrc(bbyte,n)
- byte bbyte(*)
- integer n
- c updates the Cyclic Redundancy Code
- c uses x^16 + x^12 + x^5 + 1 as recommended by CCITT
- c and as used by CRCSUBS version 1.20 for 8080 microprocessor
- c and incorporated into the MODEM7 protocol of the CP/M user's group
- c
- c during sending:
- c call clrcrc
- c call updcrc for each byte
- c call fincrc to finish (or just put 2 extra zero bytes through updcrc)
- c result to send is low byte of high and low in that order.
- c
- c during reception:
- c call clrcrc
- c call updcrc all bytes PLUS the two received CRC bytes must be passed
- c to this routine
- c then zero in high and low means good checksum
- c
- c see Computer Networks, Andrew S. Tanenbaum, Prentiss-Hall, 1981
- c
- c must declare integer to allow shifting
- integer byte
- integer high
- integer low
- common /crcval/high,low
- integer bit,bitl,bith
-
- c write(8,*) ' inside updcrc'
- do i=1,n
- c write(8,*) high,low,byte'
- c write(8,1000),high,low,bbyte
- 1000 format(3z10)
- byte=bbyte(i)
-
- do j=1,8
- c get high bits of bytes so we don't lose them when shift
- c positive is left shift
- bit =ishft( iand(128,byte), -7)
- bitl=ishft( iand(128,low), -7)
- bith=ishft( iand(128,high), -7)
- c write(8,*) 'bit,bitl,bith'
- c write(8,1000),bit,bitl,bith
- c get ready for next iteration
- newbyte=ishft(byte,1)
- byte=newbyte ! introduced dummy variable newb
- ! to avoid "access violation"
- c write(8,*) ' byte ready for next iteration'
- c write(8,1000),byte
- c shift those bits in
- low =ishft(low ,1)+bit
- high=ishft(high,1)+bitl
- c write(8,*),' high,low after shifting bits in'
- c write(8,1000),high,low
-
- if(bith.eq.1) then
- high=ieor(16,high)
- low=ieor(33,low)
- c write(8,*) ' high,low after xor'
- c write(8,1000) high,low
- endif
- enddo
- enddo
- return
- end
- c-----------------------------------------------------------
- c subroutine fincrc
- c finish CRC calculation for sending result in high, low
- c merely runs updcrc with two zero bytes
- c integer high,low
- c common /crcval/high,low
- c
- c byte=0
- c call updcrc(byte)
- c call updcrc(byte)
- c return
- c end
- c-----------------------------------------------------------
- SUBROUTINE TTYIN(LINE,N)
- BYTE LINE(*)
- INTEGER N
- C READ CHARACTERS FROM TERMINAL
- C MODIFIED BY BELONIS TO REMOVE PRIVILEGE
- C MAY HAVE PROBLEM WITH TYPE-AHEAD
- c should convert to time-out properly with loops in main ?
- INCLUDE 'QIO.DCK'
- c INCLUDE '($SSDEF)'
- parameter ss$_timeout='22c'x
- INTEGER I
- INTEGER SYS$QIOW
- INTEGER*4 terminators(2)
-
- c logical crc
- c integer checksum
- c common /checks/checksum,crc
-
- EXTERNAL IO$M_NOECHO,IO$_TTYREADALL,IO$M_TIMED
- DATA terminators/0,0/
- C
- write(8,*) ' inside ttyin, N=',N
- I = SYS$QIOW(, !EVENT FLAG
- - %VAL(CHAN), !CHANNEL
- - %VAL(%LOC(IO$_TTYREADALL).OR.
- - %LOC(IO$M_NOECHO)), ! .OR.%LOC(IO$M_TIMED)),
- - STATUS,,,
- - LINE, !BUFFER
- - %VAL(N), !LENGTH
- - , ! max time beware other disk time
- - ! and Quit or Retry time
- - terminators,,) !no terminators
- c if(crc) then
- c write(8,1000) (LINE(j),j=1,N)
- c write(8,*) ' status=',STATUS
- c else
- c write(8,2000) (line(j),j=1,N)
- c write(8,*) ' status=',status
- c endif
- 1000 format(' ttyin=',6(20z3/),10z3)
- 2000 format(' ttyin=',6(20z3/),9z3)
- c if(STATUS(1).EQ.SS$_TIMEOUT) THEN
- c write(8,*) ' 10 second timeout in ttyin'
- c print*, ' 10 second timeout in ttyin'
- c call exit
- c endif
-
- IF (I) THEN
- c write(8,*) ' returning from ttyin'
- return
- endif
- C
- C ERROR
- write(8,*) ' ttyin error.'
- CALL SYS$EXIT( %VAL(I) )
- END
- c-----------------------------------------------------------
- subroutine eat
- c eats extra characters 'til 1 second pause used to re-synch after error
- byte buffer(135)
- integer numchar
- logical i,ttyinlim
- c
- parameter maxtime=1
- c in case mis-interpreted header, allow at least 1 block of garbage
- numchar=135
-
- i=ttyinlim(buffer,numchar,maxtime)
- c print*,' finished eating'
- c write(8,*) ' finished eating'
- return
- end
- c-----------------------------------------------------------
- LOGICAL FUNCTION TTYINLIM(LINE,N,LIMIT)
- BYTE LINE(*)
- INTEGER N,LIMIT
- C READ CHARACTERS FROM TERMINAL
- C WITH TIME LIMIT, RETURN FALSE IF NO CHARACTERS
- C RECEIVED FOR LIMIT SECONDS
- C MODIFIED BY BELONIS TO REMOVE PRIVILEGE PROBLEM
- C MAY HAVE PROBLEM WITH TYPE-AHEAD
- INCLUDE 'QIO.DCK'
- c INCLUDE '($SSDEF)' ! defines error status returns
- parameter ss$_timeout='22c'x
- INTEGER I
- INTEGER SYS$QIOW
- INTEGER*4 terminators(2)
- EXTERNAL IO$M_NOECHO,IO$_TTYREADALL,IO$M_TIMED
- DATA TERMINATORS/0,0/
- C
- c write(8,*) ' inside ttyinlim'
- TTYINLIM=.TRUE. ! DEFAULT no delay over LIMIT seconds
- I = SYS$QIOW(, !EVENT FLAG
- - %VAL(CHAN), !CHANNEL
- - %VAL(%LOC(IO$_TTYREADALL).OR.
- - %LOC(IO$M_NOECHO).OR.%LOC(IO$M_TIMED)),
- - STATUS,,,
- - LINE, !BUFFER
- - %VAL(N), !LENGTH
- - %VAL(LIMIT), !time limit in seconds
- - terminators,,) !no terminators
- c print*,' ttyinlim=',(LINE(j),j=1,N), ' STATUS=',STATUS
- c write(8,*) ' ttyinlim=',(LINE(j),j=1,N), ' STATUS=',STATUS
- if(STATUS(1).EQ.SS$_TIMEOUT) THEN
- TTYINLIM=.FALSE.
- write(8,*) ' timeout'
- return
- ENDIF
-
- IF (I) THEN
- c write(8,*) ' returning from ttyinlim'
- return
- endif
- C
- C ERROR
- write(8,*) ' ttyinlim error.'
- CALL SYS$EXIT( %VAL(I) )
- END
- c-----------------------------------------------------------
- SUBROUTINE TTYOUT(LINE,N)
- BYTE LINE(*)
- INTEGER*2 N
- C output N characters without interpretation
- INCLUDE 'QIO.DCK'
- INTEGER I
- INTEGER SYS$QIOW
- EXTERNAL IO$M_NOFORMAT
- EXTERNAL IO$_WRITEVBLK
- C
- IF ( N.LE.0 ) RETURN
- C
- c print *, ' to be sent by ttyout ', line(1)
- I = SYS$QIOW(,
- - %VAL(CHAN),
- - %VAL(%LOC(IO$_WRITEVBLK).OR.
- - %LOC(IO$M_NOFORMAT)),
- - STATUS,,,
- - LINE,
- - %VAL(N),,
- - %VAL(0),, ) !NO CARRIAGE CONTROL
- if(I) then
- return
- endif
- C
- C ERROR
- write(8,*) ' ttyout error.'
- CALL SYS$EXIT( %VAL(I) )
- END
- c--------------------------------------------------
- subroutine giveup
- c this exit routine used especially in case exited via QIO problem
- include 'qio.dck'
-
- c note: if want log file message, must re-open since
- c system already closed all files before this exit handler got control
- c open(8,file='XMODEM.LOG',access='APPEND')
- c write(8,*) ' Exit handler.'
-
- c turn off passall
- call passall(CHAN,.FALSE.)
- return
- end
- c-----------------------------------------------------
- SUBROUTINE PASSALL(CHAN,SWITCH)
- C sets PASSALL mode for terminal connected to chanel CHAN, ON if switch true
- IMPLICIT INTEGER (A-Z)
- c INCLUDE '($TTDEF)'
- parameter tt$m_passall=1
- parameter tt$m_eightbit='8000'x
- parameter io$_sensemode='27'x
- parameter io$_setmode='23'x
- c INCLUDE '($IODEF)'
- LOGICAL SWITCH
- COMMON/CHAR/CLASS,TYPE,WIDTH,CHARAC(3),LENGTH !byte reversed LENGTH
- BYTE CLASS,TYPE,CHARAC,LENGTH
- INTEGER*2 WIDTH,SPEED
- EQUIVALENCE(CHARACTER,CHARAC)
-
- c sense current terminal driver mode
- ISTAT=SYS$QIOW(,%VAL(CHAN),%VAL(IO$_SENSEMODE),,,,
- 1 CLASS,,,,,)
- IF (.NOT.ISTAT) CALL ERROR('TERMINAL SENSEMODE',ISTAT)
-
- IF(SWITCH) THEN
- c turn on 8 bit passall
- CHARACTER=CHARACTER.OR.TT$M_PASSALL.OR.
- 1 TT$M_EIGHTBIT
- ELSE
- c turn off 8 bit passall
- CHARACTER=CHARACTER.AND..NOT.TT$M_PASSALL.AND.
- 1 .NOT.TT$M_EIGHTBIT
- ENDIF
- SPEED=0 !LEAVE SPEED UNCHANGED
- PAR=0 !LEAVE PARITY UNCHANGED
-
- c set terminal mode with desired passall
- ISTAT=SYS$QIOW(,%VAL(CHAN),%VAL(IO$_SETMODE),,,,
- 1 CLASS,,%VAL(SPEED),,%VAL(PAR),)
- IF (.NOT.ISTAT) CALL ERROR('TERMINAL SETMODE',ISTAT)
- RETURN
- END
- c---------------------------------------------------
- SUBROUTINE ERROR(STRING,MSGID)
- c Types error message
- IMPLICIT INTEGER(A-Z)
- CHARACTER*(*) STRING
- CHARACTER*80 MESSAGE
-
- TYPE *,' *** ERROR: ',STRING
- write(8,*) ' *** ERROR: ',STRING
- CALL SYS$GETMSG(%VAL(MSGID),MSGLEN,MESSAGE,%VAL(15),)
- TYPE *,MESSAGE(1:MSGLEN),CRLF
- write(8,*) MESSAGE(1:MSGLEN),CRLF
- RETURN
- END
- c-----------------------------------------------------------
- subroutine cancel
- INCLUDE 'QIO.DCK'
- c called to cancel send (at least)
- logical charintime,ttyinlim
- byte c
- parameter CAN=24
- parameter SPACE=32
-
- c eat garbage
- 100 charintime=ttyinlim(c,1,1)
- if(.NOT.charintime) goto 100
- c cancel other end
- call ttyout(CAN,1)
-
- c eat garbage in case it didn't understand ?
- 200 charintime=ttyinlim(c,1,1)
- if(.NOT.charintime) goto 200
- c clear the CAN from far end's input ???? why ? xmodem50.asm does it
- call ttyout(SPACE,1)
-
- c print*,' XMODEM program canceled'
- write(8,*)' XMODEM program canceled'
- call exit
- end
- c------------------------------------------------------
- subroutine getack(acked)
- c returns .TRUE. if gets ACK
- logical charintime, ttyinlim, acked
- byte sector(130),c
-
- integer errorcount
- common /err/errorcount
-
- parameter ACK=6
- parameter errlim=10 ! max number of errors
- parameter eotlim=10 ! seconds to wait for eot
-
- c print*,' inside getack'
- c empty typeahead in case garbage
- c charintime=ttyinlim(sector,130,0)
- c allow time for file close at other end.
- charintime=ttyinlim(c,1,eotlim)
- c print*,' getack got',c
- if( .NOT.charintime .OR. c.NE.ACK ) then
- c print*, ' not ACK, decimal=',c
- write(8,*) ' not ACK, decimal=',c
- errorcount=errorcount+1
- if(errorcount.GE.errlim) then
- write(8,*) ' not acknowleged in 10 tries.'
- print*,' Can''t send sector. Aborting.'
- call exit
- endif
- acked=.FALSE.
- else
- c received ACK
- acked=.TRUE.
- endif
- return
- end
-